//Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using Eas.WebCrawler.Interfaces;

namespace Eas.WebCrawler.Model.Core {
    internal class BaseRequestStore : Eas.WebCrawler.Interfaces.RequestStore {
        Queue<Request> _PriorityRequests;
        Eas.WebCrawler.Common.Collections.BinaryHeap<Eas.WebCrawler.Interfaces.Request> _Requests;
        Dictionary<Uri, object> _History;
        Eas.WebCrawler.Interfaces.WebCrawlerContext _Context;
        object _Lock;

        public BaseRequestStore() {
            _Lock = new object();
            _History = new Dictionary<Uri, object>();
        }

        #region RequestStore Members
        public void AddPriorityRequest(Request request) {
            lock (_Lock) {
                _PriorityRequests.Enqueue(request);
            }
        }

        public bool AddRequest(string uri, Eas.WebCrawler.Interfaces.Request parent) {
            if (uri == null || uri.Trim().Length==0) return false;

            return AddRequest(new Eas.WebCrawler.Interfaces.Request(uri, parent));
        }

        public bool AddRequest(Uri uri, Eas.WebCrawler.Interfaces.Request parent) {
            return AddRequest(new Eas.WebCrawler.Interfaces.Request(uri, parent));
        }

        public bool AddRequest(Eas.WebCrawler.Interfaces.Request request) {
            lock (_Lock) {
                if (_History.ContainsKey(request.Uri))
                    return false;
                _Requests.Add(request);
                _History.Add(request.Uri, null);
                return true;
            }
        }

        public void AddRange(IEnumerable<string> requests) {
            lock (_Lock) {
                _Requests.AddRange(FilterUnusedRequestsAndAddToHistory(requests));
            }
        }

        public Eas.WebCrawler.Interfaces.Request PopRequest() {
            lock (_Lock) {
                if (_PriorityRequests.Count > 0)
                    return _PriorityRequests.Dequeue();
                if (_Requests.Count == 0) return null;
                return _Requests.Pop();
            }
        }

        public int Count {
            get {
                lock (_Lock) {
                    return _Requests.Count + _PriorityRequests.Count;
                }
            }
        }

        public bool HasRequests {
            get {
                return Count > 0;
            }
        }

        #endregion

        #region WebCrawlerComponent Members

        public void Initialize(Eas.WebCrawler.Interfaces.WebCrawlerContext context) {
            if (context == null)
                throw new ArgumentNullException("context");
            _Context = context;
            _Context.Events.Starting+=new EventHandler(Start);
            _Context.Events.Stopped+=new EventHandler(Stop);
        }

        #endregion

        private  void Start(object sender, System.EventArgs args) {
            _PriorityRequests = new Queue<Request>();
            _Requests = new Eas.WebCrawler.Common.Collections.BinaryHeap<Request>(_Context.RequestPriorityComparer);
            lock (_Lock) {
                foreach (Uri uri in _Context.CompletedRequestHistory.GetCompletedRequests()) {
                    if (!_History.ContainsKey(uri))
                        _History.Add(uri, null);
                }
            }
            AddRange(_Context.StartingUris);
        }

        private void Stop(object sender, System.EventArgs args) {
            _PriorityRequests.Clear();
            _Requests.Clear();
            _History.Clear();
        }


        private IEnumerable<Request> FilterUnusedRequestsAndAddToHistory(IEnumerable<string> requests) {
            foreach (string request in requests) {
                if (string.IsNullOrEmpty(request)) continue;

                Uri requestUri = new Uri(request, UriKind.RelativeOrAbsolute);
                if (!_History.ContainsKey(requestUri)) {
                    _History.Add(requestUri, null);
                    yield return new Request(request, null);
                }
            }
        }
    }
}
